package common

import (
	"crypto/rand"
	"encoding/binary"
	"io"
)

// Frame 表示一个 WebSocket 帧
type Frame struct {
	Fin     bool    // 是否为消息的最后一帧
	Opcode  Opcode  // 帧类型
	Masked  bool    // 是否使用掩码（客户端发送的帧必须掩码，服务端发送的帧必须不掩码）
	Mask    [4]byte // 掩码密钥（仅客户端发送时有效）
	Payload []byte  // 载荷数据
}

// 从 reader 中解析一个 WebSocket 帧
func decodeFrameFromReader(r io.Reader, isClient bool) (*Frame, error) {
	var header [2]byte
	if _, err := io.ReadFull(r, header[:]); err != nil {
		return nil, err
	}

	// 解析第一个字节：Fin(1bit) + RSV1-3(3bit) + Opcode(4bit)
	fin := (header[0] & 0x80) != 0
	opcode := Opcode(header[0] & 0x0F)

	// 检查 Opcode 的合法性
	if err := checkOpcode(opcode); err != nil {
		return nil, err
	}

	// 解析第二个字节：Mask(1bit) + PayloadLen(7bit)
	masked := (header[1] & 0x80) != 0

	// 检查掩码要求：客户端接收的帧必须不掩码，服务端接收的帧必须掩码
	// (isClient && masked) || (!isClient && !masked)
	if isClient == masked {
		return nil, ErrMaskRequired
	}

	payloadLen7 := int(header[1] & 0x7F)

	// 计算实际载荷长度（处理 7bit/16bit/64bit 三种情况）
	var payloadLen int64 // 先用 int64 暂存，避免溢出
	switch payloadLen7 {
	case 126:
		// 16 位扩展长度：读取 2 字节（大端序）
		var len16 uint16
		if err := binary.Read(r, binary.BigEndian, &len16); err != nil {
			return nil, err
		}
		payloadLen = int64(len16)
	case 127:
		// 64 位扩展长度：读取 8 字节（大端序）
		var len64 int64
		if err := binary.Read(r, binary.BigEndian, &len64); err != nil {
			return nil, err
		}
		payloadLen = len64
	default:
		// 7 位长度：直接使用
		payloadLen = int64(payloadLen7)
	}

	// 检查载荷长度是否超过当前系统 int 类型的最大值（避免转换溢出）
	maxAllowed := maxIntValue()
	if payloadLen > maxAllowed {
		return nil, ErrPayloadTooLarge
	}

	// 读取掩码（如果有）
	var mask [4]byte
	if masked {
		if _, err := io.ReadFull(r, mask[:]); err != nil {
			return nil, err
		}
	}

	// 读取载荷数据
	payload := make([]byte, payloadLen)
	if _, err := io.ReadFull(r, payload); err != nil {
		return nil, err
	}

	// 对载荷数据进行解掩码（如果有）
	if masked {
		maskPayload(payload, mask)
	}

	return &Frame{
		Fin:     fin,
		Opcode:  opcode,
		Masked:  masked,
		Mask:    mask,
		Payload: payload,
	}, nil
}

// 将 Frame 编码为字节流并写入 writer
func encodeFrameAndWrite(w io.Writer, frame *Frame, isClient bool) error {
	// 检查 Opcode 的合法性
	if err := checkOpcode(frame.Opcode); err != nil {
		return err
	}

	// 第一个字节：Fin(1bit) + Opcode(4bit)（忽略RSV）
	var header [2]byte
	if frame.Fin {
		header[0] |= 0x80
	}
	header[0] |= byte(frame.Opcode)

	// 检查掩码要求：客户端发送的帧必须掩码，服务端发送的帧必须不掩码
	// (isClient && !frame.Masked) || (!isClient && frame.Masked)
	if isClient != frame.Masked {
		return ErrMaskRequired
	}

	// 第二个字节：Mask(1bit) + PayloadLen(7bit)
	payloadLen := len(frame.Payload)
	if frame.Masked {
		header[1] |= 0x80
	}

	// 处理载荷长度
	switch {
	case payloadLen < 126:
		header[1] |= byte(payloadLen)
	case payloadLen <= 0xFFFF:
		header[1] |= 126
		if err := binary.Write(w, binary.BigEndian, uint16(payloadLen)); err != nil {
			return err
		}
	default:
		header[1] |= 127
		if err := binary.Write(w, binary.BigEndian, int64(payloadLen)); err != nil {
			return err
		}
	}

	// 写入头部前两个字节
	if _, err := w.Write(header[:]); err != nil {
		return err
	}

	// 写入掩码（如果有）
	if frame.Masked {
		// 生成随机4字节掩码
		_, err := rand.Read(frame.Mask[:])
		if err != nil {
			panic(err)
		}

		// 写入掩码
		if _, err := w.Write(frame.Mask[:]); err != nil {
			return err
		}

		// 对载荷数据进行掩码处理
		maskPayload(frame.Payload, frame.Mask)
	}

	// 写入载荷数据
	_, err := w.Write(frame.Payload)
	return err
}
